package fun.ticsmyc.tmall.item.order.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import fun.ticsmyc.rpc.client.annotation.RpcClient;
import fun.ticsmyc.tmall.common.pojo.PageResult;
import fun.ticsmyc.tmall.common.utils.IdWorker;
import fun.ticsmyc.tmall.item.api.GoodsService;
import fun.ticsmyc.tmall.item.order.TmallOrderApplication;
import fun.ticsmyc.tmall.item.order.mapper.OrderMapper;
import fun.ticsmyc.tmall.item.order.service.OrderService;
import fun.ticsmyc.tmall.item.order.util.ThreadPoolManager;
import fun.ticsmyc.tmall.item.pojo.Goods;
import fun.ticsmyc.tmall.item.pojo.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Ticsmyc
 * @date 2020-08-10 10:56
 */
@Component
public class OrderServiceImpl implements OrderService {
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
    private static ThreadPoolManager threadPoolManager = ThreadPoolManager.newInstance();

    private static final String REDIS_ORDER_PREFIX = "ORDER:PAYMENT:";
    private static final String REDIS_USER_PREFIX = "ORDER:USER:";
    private static final String RABBITMQ_EXCHANGE_NAME = "ORDER.EXCHANGE";

    @RpcClient(group="default")
    private GoodsService goodsService;

    @Autowired
    private OrderMapper orderMapper;


    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RedisTemplate<String, Order> orderRedisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ObjectMapper objectMapper;


    /**
     * 创建订单  返回订单id
     * @param order
     * @return
     */
    public Long createOrder(Order order)  {
        //1. 使用Idworker生成订单号
        long orderId = idWorker.nextId();
        order.setId(orderId);
        order.setState("等待生成付款信息");
        //2. 订单加入redis缓存
        orderRedisTemplate.opsForValue().set(REDIS_ORDER_PREFIX+orderId+"",order,15, TimeUnit.MINUTES);
        stringRedisTemplate.opsForZSet().add(REDIS_USER_PREFIX+order.getUserId(),orderId+"",orderId);
        //3.异步生成付款信息，更新redis
        Runnable generatePaymentInformation = ()->{
            //异步生成付款信息
            order.setState("待付款");

            //TODO:这里调用第三方接口生成付款方式
            logger.debug("为"+orderId+"生成付款信息，存入redis");
            //(假装已经生成付款信息了 )
            order.setPayment("这里是生成好的付款信息");
            orderRedisTemplate.opsForValue().set(REDIS_ORDER_PREFIX+orderId,order,15, TimeUnit.MINUTES);
        };
        threadPoolManager.addExecuteTask(generatePaymentInformation);

        return orderId;
    }



    /**
     * 完成付款，从redis中删除订单，存入mysql
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean finishPayment(Long id) {
        //1.先从redis中拿到订单信息
        Order orderFromRedis = this.getOrderFromRedisByOrderId(id);
        if(orderFromRedis == null){
            //redis中没有这个订单，已经被支付或者取消了
            return true;
        }
        orderFromRedis.setState("已支付");
            //修改状态后写回redis
        orderRedisTemplate.opsForValue().set(REDIS_ORDER_PREFIX+id+"",orderFromRedis,15, TimeUnit.MINUTES);

        //2.订单信息写入mysql
        Map<String,String> msg = new HashMap<>();
        msg.put("method","insert");
        try {
            msg.put("order",objectMapper.writeValueAsString(orderFromRedis));
        } catch (JsonProcessingException e) {
            logger.error("序列化失败"+orderFromRedis);
        }
        amqpTemplate.convertAndSend(RABBITMQ_EXCHANGE_NAME,"order",msg);
//        //3. 在异步写入完成后，删除redis中的信息
//        orderRedisTemplate.delete(REDIS_ORDER_PREFIX+id);
        return true;
    }



    /**
     * 根据用户id查询订单。
     * @param userId
     * @param state
     * @return
     */
    public List<Order> getOrderByUserId(String userId, Integer state) {
        List<Order> orders = new ArrayList<>();
        switch (state){
            case 0:
                //查询所有订单
                orders.addAll(getOrderFromRedisByUserId(userId));
                orders.addAll(getOrderFromMysqlByUserId(userId));
                break;
            case 1:
                //未支付订单
                getOrderFromRedisByUserId(userId).forEach(order ->{
                    if("待付款".equals(order.getState())){
                        orders.add(order);
                    }
                });
                break;
            case 2:
                //已支付订单
                getOrderFromRedisByUserId(userId).forEach(order ->{
                    if("已支付".equals(order.getState())){
                        orders.add(order);
                    }
                });
                getOrderFromMysqlByUserId(userId).forEach(order ->{
                    orders.add(order);
                });
                break;
        }
        return orders;
    }
    /**
     * 根据订单号查询订单
     * @param id
     * @return
     */
    public Order getOrderByOrderId(Long id) {
        Order orderFromRedisByOrderId = this.getOrderFromRedisByOrderId(id);
        if(orderFromRedisByOrderId != null){
            return orderFromRedisByOrderId;
        }
        Order orderFromMysqlByOrderId = this.getOrderFromMysqlByOrderId(id);
        if(orderFromMysqlByOrderId != null){
            return orderFromMysqlByOrderId;
        }
        return null;
    }

    /**
     * 根据用户名从redis中查询订单
     * @param userId
     * @return
     */

    private List<Order> getOrderFromRedisByUserId(String userId){
        List<Order> orders = new ArrayList<>();
        Set<String> range = stringRedisTemplate.opsForZSet().range(REDIS_USER_PREFIX + userId, 0, -1);
        range.forEach((id)->{
            Order order = orderRedisTemplate.opsForValue().get(REDIS_ORDER_PREFIX + id);
            if(order != null){
                orders.add(order);
            }else{
                //清理空的用户名->订单号 索引
                stringRedisTemplate.opsForZSet().remove(REDIS_USER_PREFIX + userId,id);
            }
        });
        return orders;
    }

    /**
     * 根据用户名从mysql中查询订单
     * @param userId
     * @return
     */
    private List<Order> getOrderFromMysqlByUserId(String userId){
        Order record = new Order();
        record.setUserId(userId);
        List<Order> orders = orderMapper.select(record);
        return orders;
    }

    /**
     * 根据订单号从Redis查询订单 （查询未付款订单）
     * @param id
     * @return
     */
    private Order getOrderFromRedisByOrderId(Long id) {
        Order order = orderRedisTemplate.opsForValue().get(REDIS_ORDER_PREFIX + id);
        return order;
    }

    /**
     * 从mysql中查询订单 【已支付订单】
     * @param id
     * @return
     */

    public Order getOrderFromMysqlByOrderId(Long id) {
        Order order = this.orderMapper.selectByPrimaryKey(id);
        return order;
    }


    /**
     * 持久化后，删除redis中缓存的订单信息
     * @param id
     * @param userId
     */
    @Transactional
    public void deleteOrderInRedis(Long id,String userId){
        //删除订单信息
        orderRedisTemplate.delete(REDIS_ORDER_PREFIX+id);
        //删除用户->订单号 索引
        stringRedisTemplate.opsForZSet().remove(REDIS_USER_PREFIX+userId,id+"");
    }
    /**
     * 取消未付款订单
     * @param id
     */

    public void deleteOutstandingOrder(Long id,String userId) {
        deleteOrderInRedis(id,userId);
    }

    /**
     * 订单信息写入mysql
     * @param order
     */
    public void insertOrder(Order order){
        this.orderMapper.insert(order);
    }



}
